/**
 *原理：
 * 1. 使用自执行函数创建Person类，变量privateData和privateId被所有实例共享；
   2. privateData用来储存每个实例的私有属性name的key-value，privateId用来分配每个实例的唯一标识符_id；
   3.方法getName存在于prototype上，被所有实例共享

   优点：方法getName存在于prototype上，被所有实例共享
   缺点：散列表privateData对每个实例都是强引用，导致实例不能被垃圾回收处理。如果存在大量实例必然会导致memory leak。

 * @param {*} name  以一个name属性为例
 * @returns
 */
let Person = (function () {
  // 定义一个对象保存对应关系
  let privateData = {};
  let privateId = 0;

  function Person(name) {
    // _id是特殊标记，用以取值
    Object.defineProperty(this, "_id", {
      value: privateId++,
    });
    // 然后将值放置存储对象
    privateData[this._id] = { name: name };
  }

  Person.prototype.getName = function () {
    // 取值需要通过特殊标记去存储对象中取，这样外面无法直接获取到
    return privateData[this._id]["name"];
  };

  return Person;
})();

let p = new Person("kele");
console.log("[ p.getName() ] >", p.getName());
